package net.towee.server.persistence;

import java.util.Date;
import java.util.List;

import net.towee.model.ProfileContainer;
import net.towee.model.repo.DocumentData;
import net.towee.model.repo.DocumentIdentity;
import net.towee.model.repo.DocumentPatch;
import net.towee.model.repo.DocumentType;
import net.towee.model.repo.NodeData;
import net.towee.model.repo.TreeNode;
import net.towee.shared.exceptions.PersistenceException;

public interface DocumentStore {
	/**
	 * Document with given id
	 * 
	 * @param id
	 * @return
	 * @throws PersistenceException 
	 */
	DocumentData getDocument(String id) throws PersistenceException;

	/**
	 * Get document with given id and with some fields
	 * 
	 * @param id
	 * @param fields
	 * @return
	 * @throws PersistenceException 
	 */
	DocumentData getDocument(String id, String... fields) throws PersistenceException;

	/**
	 * Return all documents page by page in last update ordering
	 * 
	 * @param offset
	 * @param perpage
	 * @return
	 */
	List<DocumentData> getDocuments(int offset, int perpage);

	/**
	 * 
	 * @param offset
	 * @param perpage
	 * @param types
	 * @return list of documents with some type in types container. Documents
	 *         sorted by update date field.
	 */
	List<DocumentData> getDocuments(int offset, int perpage, DocumentType... types);

	/**
	 * 
	 * @param offset
	 * @param perpage
	 * @param groupId
	 * @param types
	 * @return list of documents with some type in types container from given
	 *         groups. If groups is null it ignored. Documents sorted by update
	 *         date field.
	 */
	List<DocumentData> getDocuments(int offset, int perpage, Iterable<String> groupId, Iterable<DocumentType> types);
	
	/**
	 * Return number of documents with given options start at given date 
	 * @return
	 */
	int getRecentDocumentsCount(Date startDate, Iterable<String> groupId, Iterable<DocumentType> types);

	/**
	 * Remove document and all referenced data(identity, attachments, etc.)
	 * @param id
	 * @return true on success
	 * @throws PersistenceException 
	 */
	boolean removeDocument(String id) throws PersistenceException;
	
	/**
	 * Return root tree of some group
	 * 
	 * @param groupId
	 * @return
	 */
	List<NodeData> getRootTree(String groupId);

	/**
	 * Get subtree of some node
	 * @param groupId 
	 * @param nodeId
	 * 
	 * @return
	 */
	List<NodeData> getSubTree(String groupId, String nodeId);

	/**
	 * Return subtree of node with given path
	 * @param groupId TODO
	 * @param path
	 * 
	 * @return
	 */
	List<NodeData> getSubTreeByPath(String groupId, String path);
	
	/**
	 * Return subtree of node with given path
	 * @param groupId TODO
	 * @param path
	 * @return
	 */
	List<NodeData> getAllSubTreesByPath(String groupId, String path);

	/**
	 * Return all subtrees start from root and end on subtree where node with
	 * given id is.
	 * @param groupId TODO
	 * @param nodeId
	 * 
	 * @return
	 * @throws PersistenceException 
	 */
	List<NodeData> getSubTreesToPath(String groupId, String nodeId) throws PersistenceException;

	/**
	 * Trash of some group
	 * 
	 * @param groupId
	 * @return
	 */
	List<NodeData> getTrash(String groupId);

	/**
	 * Put to trash nodes with given id. It also mark all subtrees and documents
	 * as trash.
	 * @param groupId TODO
	 * @param nodeId
	 * @throws PersistenceException 
	 */
	void putToTrash(String groupId, String... nodeId) throws PersistenceException;

	/**
	 * Add tree node to node with given id. If parentNode is null it add node to
	 * root tree of group
	 */
	void saveNode(TreeNode parentNode);
	
	/**
	 * Get node with given id
	 *  
	 * @param id
	 * @return
	 * @throws PersistenceException 
	 */
	NodeData getNode(String id) throws PersistenceException;

	/**
	 * Set new name of tree node. New name must be unique in subtree. It also
	 * change all paths in all subtrees (unfortunately).
	 * @param groupId TODO
	 * @param nodeId
	 * @param newName
	 * 
	 * @return
	 * @throws PersistenceException 
	 */
	boolean renameNode(String groupId, String nodeId, String newName) throws PersistenceException;

	/**
	 * Remove node with given id and all subtrees. It also remove all dependent
	 * documents, attachments and patches.
	 * @param groupId TODO
	 * @param nodeId
	 * 
	 * @return true on success
	 * @throws PersistenceException 
	 */
	boolean removeNode(String groupId, String nodeId) throws PersistenceException;
	boolean removeNode(String groupId, List<String> nodeIds) throws PersistenceException;

	/**
	 * Move nodes to new subtree. It MUST move only in one goroup.
	 * Nodes movement between different groups are NOT ALOWED.  
	 * @param groupId TODO
	 * @param newParentNode
	 * @param nodeId
	 * 
	 * @throws PersistenceException 
	 */
	void moveNodes(String groupId, String newParentNode, String... nodes) throws PersistenceException;

	/**
	 * Document patch with some id
	 * 
	 * @param id
	 * @return
	 */
	DocumentPatch getDocumentPatch(String id);

	/**
	 * @param id
	 * @return identity of some document
	 * @throws PersistenceException TODO
	 */
	DocumentIdentity getDocumentIdentity(String id) throws PersistenceException;

	/**
	 * Find documents in name by given string. If groupId is null it search in
	 * all groups. If document type is null it search in all types. If authorId
	 * is null it ignore author field.
	 * 
	 * @param str
	 * @param groupId
	 * @param authorId
	 * @param type
	 * @return
	 */	
	List<DocumentData> findDocuments(String str, Iterable<String> groupId, String authorId,
			Iterable<DocumentType> type, int offset, int limit);

	/**
	 * Find document by profile
	 * 
	 * @param groupId
	 * @param authorId
	 * @param type
	 * @param profile
	 * @param offset
	 * @param limit
	 * @return
	 */
	List<DocumentData> findDocumentsByProfile(String groupId, String authorId, DocumentType type,
			ProfileContainer profile, int offset, int limit);

	/**
	 * It create new document(create document identity first) and new tree node.
	 * Tree node object must be in document data.
	 * 
	 * @param doc
	 */
	void createDocument(DocumentData doc);

	/**
	 * Change document. Implementation also add the diff to document and set new
	 * update date
	 * 
	 * @param docId
	 * @param profile
	 * @return
	 */
	boolean changeDocument(String docId, DocumentData doc);

	/**
	 * TUp! document with given ID
	 * 
	 * @param docId
	 * @param userId
	 * @return
	 */
	boolean tupDocument(String docId, String userId);
	
	/**
	 * Create document patch
	 * 
	 * @param p
	 */
	void createPatch(DocumentPatch p);

	/**
	 * Get node by it path and name
	 * @param groupId TODO
	 * @param join
	 * @param string
	 * 
	 * @return TODO
	 */
	NodeData getNodeByPath(String path, String nodeName, String groupId);

	/**
	 * Return map of patches where key is id of patch
	 * 
	 * @param neededPatchs
	 * @return
	 */
	List<DocumentPatch> getDocumentPatchs(List<String> neededPatchs);
	
	/**
	 * Return true if node in group repo with given path and name exists.
	 * @param parentId
	 * @param name
	 * @return
	 */
	boolean checkNodeWithNameExisting(String groupId, String parentId, String name);

	/**
	 * Get list of nodes with given ids
	 * @param groupId TODO
	 * @param nodeIds
	 * @return
	 */
	List<NodeData> getNodes(String groupId, List<String> nodeIds);
}